package com.yuyou.fn.educational.service.impl;

import cn.beststudy.member.ArrayOfMemberProfileDTOByGetAccount;
import cn.beststudy.member.MemberProfileDTOByGetAccount;
import cn.beststudy.member.RegistrationService;
import cn.beststudy.member.RegistrationServiceSoap;
import com.github.wens.framework.service.impl.SuperServiceImpl;
import com.github.wens.mybatisplus.examples.Example;
import com.google.common.collect.Lists;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.service.ISiteConfigService;
import com.yuyou.fn.common.util.*;
import com.yuyou.fn.educational.entity.BaseGrade;
import com.yuyou.fn.educational.entity.CustomerBindStudent;
import com.yuyou.fn.educational.entity.Student;
import com.yuyou.fn.educational.mapper.CustomerBindStudentMapper;
import com.yuyou.fn.educational.service.IBaseGradeService;
import com.yuyou.fn.educational.service.ICustomerBindStudentService;
import com.yuyou.fn.educational.service.ICustomerUserService;
import com.yuyou.fn.educational.service.IStudentService;
import com.yuyou.fn.educational.vo.CustomerBindStudentVo;
import com.yuyou.fn.educational.vo.StudentSaveOrUpdateVo;
import com.yuyou.fn.platform.entity.CustomerUser;
import com.zy.otuc.AuthHandler;
import com.zy.otuc.UCOutWebService;
import com.zy.otuc.UserWebServiceService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

/**
 *
 * CustomerBindStudent 表数据服务层接口实现类
 *
 */
@Service
public class CustomerBindStudentServiceImpl extends SuperServiceImpl<CustomerBindStudentMapper, CustomerBindStudent,Long> implements ICustomerBindStudentService {

    private final Logger log = LoggerFactory.getLogger(CustomerBindStudentServiceImpl.class);

    @Resource
    private IStudentService studentService;

    @Resource
    private IBaseGradeService baseGradeService;

    @Resource
    private ICustomerUserService customerUserService ;

    @Resource
    private ISiteConfigService siteConfigService ;


    private volatile RegistrationServiceSoap registrationService ;


    private RegistrationServiceSoap getRegistrationService() {

        if(registrationService != null ){
            return registrationService ;
        }
        synchronized (this){
            if(registrationService != null ){
                return registrationService ;
            }
            registrationService =  new RegistrationService(Urls.create(siteConfigService.getConfigValueFromCache("member_webservice_url"))).getRegistrationServiceSoap();
        }
        return registrationService;
    }

    @Override
    public List<CustomerBindStudentVo> findStudentsByUserIds(Long userId) {
        if (userId==null){
            return Collections.EMPTY_LIST;
        }

        CustomerUser customerUser = customerUserService.findById(userId, "memberId");

        if(StringUtils.isNotEmpty(customerUser.getMemberId())){
            Future<?> f = Threads.dispatch(() -> mergeMemberCenterBind(userId, customerUser.getMemberId()));
            try {
                f.get(30, TimeUnit.SECONDS);
            } catch (Exception e) {
                //ignore
            }
        }

        Example<CustomerBindStudent> example=CustomerBindStudent.createExample();
        example.createCriteria().andEqualTo("userId",userId);
        List<CustomerBindStudent> customerBindStudentList=findListByExample(example);
        List<Long> studentIds=BeanUtils.toList(customerBindStudentList,"studentId");

        List<CustomerBindStudentVo> customerBindStudentVoList=new ArrayList<CustomerBindStudentVo>(studentIds.size());
        List<Student> studentList=studentService.findByIds(studentIds);
        Map<Long,Student> studentMap = BeanUtils.toMap(studentList,"studentId");


        for(CustomerBindStudent bs :customerBindStudentList ){
            Student student = studentMap.get(bs.getStudentId());
            CustomerBindStudentVo  vo = new CustomerBindStudentVo();
            BeanUtils.copyProperties(vo,bs );
            BeanUtils.copyProperties(vo,student );
            vo.setStudentName(student.getName());
            customerBindStudentVoList.add(vo);
        }


        return  customerBindStudentVoList;
    }


    @Override
    public CustomerBindStudent findByStudentIdAndUserId(Long studentId,Long userId) {
        Example<CustomerBindStudent> studentExample = CustomerBindStudent.createExample();
        Example.Criteria criteria = studentExample.createCriteria();
        criteria.andEqualTo("studentId", studentId);
        criteria.andEqualTo("userId", userId);
        return  this.findOneByExample(studentExample);
    }



    @Override
    public void deleteByStudentIdAndUserId(Long studentId, Long userId) {

        Future<?> future = Threads.dispatch(() -> {
            CustomerUser customerUser = customerUserService.findById(userId, "memberId");
            Student student = studentService.findById(studentId, "cid");
            if (StringUtils.isNotEmpty(customerUser.getMemberId()) && StringUtils.isNotEmpty(student.getCid())) {
                //解绑
                try{
                    getRegistrationService().changeMem2MemRelationIsValid(customerUser.getMemberId(), student.getCid(), false);
                }catch (Exception e){
                    //
                }
            }
        });

        Example<CustomerBindStudent> studentExample = CustomerBindStudent.createExample();
        Example.Criteria criteria = studentExample.createCriteria();
        criteria.andEqualTo("studentId", studentId);
        criteria.andEqualTo("userId", userId);
        this.deleteByExample(studentExample);

        try {
            future.get(1,TimeUnit.MINUTES);
        } catch (Exception e) {
            //
        }


    }

    @Override
    public void insertByStudentId(Long studentId, Long userId) {
        Validate.notNull(studentId,"requirestudentId");
        Validate.notNull(userId,"requireuserId");
        try{
            Future<?> future = Threads.dispatch(() -> {
                CustomerUser customerUser = customerUserService.findById(userId, "memberId");
                Student student = studentService.findById(studentId, "cid");
                if (StringUtils.isNotEmpty(customerUser.getMemberId()) && StringUtils.isNotEmpty(student.getCid())) {
                    try {
                        getRegistrationService().changeMem2MemRelationIsValid(customerUser.getMemberId(), student.getCid(), true );
                    }catch (Exception e){
                        //
                    }

                }
            });

            CustomerBindStudent customerBindStudent=new CustomerBindStudent();
            customerBindStudent.setUserId(userId);
            customerBindStudent.setCreateTime(TimeUtils.now());
            customerBindStudent.setStudentId(studentId);
            customerBindStudent.setUpdateTime(TimeUtils.now());
            this.insertSelective(customerBindStudent);
            future.get(1,TimeUnit.MINUTES);
        }catch (Exception e){
            if(!e.getMessage().contains("uq_user_id_student_id")){
                throw new RuntimeException(e);
            }
        }


    }



    @Override
    public CustomerBindStudentVo findBindStudentDetail(Long studentId) {
        Student student = studentService.findById(studentId);
        CustomerBindStudentVo  vo = new CustomerBindStudentVo();
        BeanUtils.copyProperties(vo,student );
        vo.setStudentName(student.getName());
        vo.setSchoolName(student.getSchool());
        vo.setLocation(student.getLocation());
        vo.setAddress(student.getAddress());
        return vo;
    }

    @Override
    public void updateBindStudentInfo(Long studentId,Long gradeId, String school, String location, String address) {

        Validate.notNull(studentId);

        if(gradeId == null && StringUtils.isEmpty(school)  && StringUtils.isEmpty(location) && StringUtils.isEmpty(address)){
            return ;
        }

        if( ( StringUtils.isEmpty(location) && StringUtils.isNotEmpty(address) ) ||  ( StringUtils.isEmpty(address) && StringUtils.isNotEmpty(location) )){
            throw new IllegalArgumentException("Invalid location address");
        }

        Student u = new Student();
        u.setStudentId(studentId);
        u.setSchool(school);
        u.setLocation(location);
        u.setAddress(address);

        if(gradeId != null ){
            u.setGradeId(gradeId);
            u.setGradeName(baseGradeService.findGradeNameById(gradeId));
        }

        studentService.updateSelectiveById(u);

    }

    @Override
    public void addBind(Long userId, String studentName, String studentPhoneNo) {
        Student student = studentService.findByNameAndPhone(studentName, studentPhoneNo);
        if(student == null ){
            throw new BusException("学员不存在");
        }
        insertByStudentId(student.getStudentId(),userId );
    }

    @Override
    public List<CustomerBindStudent> findStudentsByCustomerUserIds(List<Long> userIds) {
        if (Utils.checkListEmpty(userIds)){
            return  Collections.EMPTY_LIST;
        }
        Example<CustomerBindStudent> studentExample = CustomerBindStudent.createExample();
        Example.Criteria criteria = studentExample.createCriteria();
        criteria.andIn("userId", userIds);
        return  this.findListByExample(studentExample);
    }


    @Override
    public void mergeMemberCenterBind(Long userId , String memberId) {

        try{
            //清除本地
            Example<CustomerBindStudent> example=CustomerBindStudent.createExample();
            example.createCriteria().andEqualTo("userId",userId);
            deleteByExample(example);


            ArrayOfMemberProfileDTOByGetAccount childMemberProfile = getRegistrationService().getChildMemberProfile(memberId);

            if(childMemberProfile != null && childMemberProfile.getMemberProfileDTOByGetAccount() != null ){

                List<MemberProfileDTOByGetAccount> members = childMemberProfile.getMemberProfileDTOByGetAccount();

                List<String> memberIDs = Lists.transform(members,item -> item.getMemberID() );

                List<Student> students = studentService.findByCIDs(memberIDs);

                Set<Long> studentIds = students.stream().map(Student::getStudentId).collect(Collectors.toSet());

                if(students.size() != memberIDs.size() ){

                    List<MemberProfileDTOByGetAccount> newMembers = new ArrayList<>(memberIDs.size());
                    for(MemberProfileDTOByGetAccount m : members ){
                        boolean f = false ;
                        for(Student student : students ){
                            if(m.getMemberID().equalsIgnoreCase(student.getCid())){
                                f = true ;
                                break;
                            }
                        }
                        if(!f){
                            newMembers.add(m);
                        }
                    }

                    List<Long> newStudentIds = newMembers.stream().parallel().map(m -> {
                        Student student = studentService.findByCID(m.getMemberID());

                        if (student == null) {
                            student = studentService.findByNameAndPhone(StringUtils.defaultIfEmpty(m.getFullName(), m.getMainPhoneNum() ), m.getMainPhoneNum());
                        }
                        if (student == null) {
                            BaseGrade baseGrade = baseGradeService.findGradeByGradeName(m.getGradeName());
                            StudentSaveOrUpdateVo studentSaveOrUpdateVo = new StudentSaveOrUpdateVo();
                            studentSaveOrUpdateVo.setName(StringUtils.defaultIfEmpty(m.getFullName(), m.getMainPhoneNum() ));
                            studentSaveOrUpdateVo.setPhoneNo(m.getMainPhoneNum());
                            studentSaveOrUpdateVo.setSex(0);
                            studentSaveOrUpdateVo.setCid(m.getMemberID());
                            if (baseGrade != null) {
                                studentSaveOrUpdateVo.setGradeId(baseGrade.getGradeId());
                                studentSaveOrUpdateVo.setGradeName(baseGrade.getGradeName());
                            }
                            return studentService.saveOrUpdateStudent(studentSaveOrUpdateVo);
                        } else {
                            return student.getStudentId();
                        }
                    }).collect(Collectors.toList());
                    studentIds.addAll(newStudentIds);
                }

                //同步到本地
                batchBind( studentIds.stream().collect(Collectors.toList()), userId );
            }
        }catch (Exception e){
            log.error("合并绑定学员失败 : user_id=" + userId ,e );
        }

    }

    @Override
    public void autoBindStudent( Long userId , String phoneNo ) {
        List<Student> studentList=studentService.findByPhone(phoneNo);
        List<Long> studentIds = BeanUtils.toList(studentList, "studentId");
        studentIds.stream().parallel().forEach(studentId -> insertByStudentId(studentId,userId));

    }

    private void batchBind(List<Long> studentIds, long userId) {

        if(studentIds.isEmpty()){
            return;
        }

        List<CustomerBindStudent> insertList=new ArrayList<>(studentIds.size());
        for (Long studentId:studentIds){
            CustomerBindStudent customerBindStudent=new CustomerBindStudent();
            customerBindStudent.setUserId(userId);
            customerBindStudent.setCreateTime(TimeUtils.now());
            customerBindStudent.setStudentId(studentId);
            customerBindStudent.setUpdateTime(TimeUtils.now());
            insertList.add(customerBindStudent);
        }

        if (insertList.size()>0){
            try{
                this.insertBatch(insertList);
            }catch (Exception e){
                try{
                    insertList.stream().forEach(s -> insertSelective(s));
                }catch (Exception ee){

                }
            }
        }
    }

    @Override
    @Transactional
    public void mergeBindByOriginAndTargetStudentId(long orginStudentId, long targetStudentId) {
        Example<CustomerBindStudent> example=CustomerBindStudent.createExample();
        example.createCriteria().andEqualTo("studentId",orginStudentId);
        List<CustomerBindStudent> list=this.findListByExample(example);
        for (CustomerBindStudent customerBindStudent:list){
            CustomerBindStudent update=new CustomerBindStudent();
            update.setBindId(customerBindStudent.getBindId());
            update.setStudentId(targetStudentId);
            update.setUpdateTime(TimeUtils.now());
            try{
                this.updateSelectiveById(update);//更新不成功，索引冲突，删除该记录。
            }catch (Exception e){
                this.deleteById(customerBindStudent.getBindId());
            }
        }
    }
}